package cn.jhz.learn.community_dynamic.model;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import cn.jhz.learn.community_dynamic.security.model.SimpleGrantedUser;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.io.Serializable;
import javax.persistence.*;

import java.util.Date;
import java.util.Set;

/**
 * The persistent class for the account_user database table.
 * 
 */
/**
 * @author machine005
 *
 */
@Entity
@Table(name = "user", schema = "community_dynamic")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class UserEntity implements Serializable, SimpleGrantedUser {
    private static final long serialVersionUID = -2203735777095094388L;
    
    private Integer id;
    private String email;
    private Long loginId;
    private String password;
    private String phone;
    private Date registrationTime;
    private Byte status;
    private String username;
    private String userpic;
    private Set<RoleEntity> roles;
    private Set<UserBindEntity> userBinds;
    private Set<PostEntity> supports;
    private Set<PostEntity> unsupports;
    private Set<CommentEntity> comments;
    private Set<ImageEntity> images;
    private Set<PostEntity> posts;
    private Set<UserEntity> follows;
    private Set<UserEntity> followeds;
    private Set<FeedbackEntity> feedbacks;
    private Set<UserEntity> black;
    private Set<UserEntity> blacked;
    private UserInfoEntity userInfo;
    
    public interface PasswordView{}

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    public Integer getId() {
	return this.id;
    }

    public void setId(Integer id) {
	this.id = id;
    }

    @Basic
    @Column(name = "email", nullable = false, length = 45)
    public String getEmail() {
	return this.email;
    }

    public void setEmail(String email) {
	this.email = email;
    }

    @Basic
    @Column(name = "login_id", nullable = false, length = 45)
    public Long getLoginId() {
	return this.loginId;
    }

    public void setLoginId(Long loginId) {
	this.loginId = loginId;
    }

    @Basic
    @Column(nullable = false, length = 128)
    public String getPassword() {
	return this.password;
    }

    public void setPassword(String password) {
	this.password = password;
    }

    @Basic
    @Column(name = "phone", nullable = false, length = 45)
    public String getPhone() {
	return this.phone;
    }

    public void setPhone(String phone) {
	this.phone = phone;
    }

    @Basic
    @Column(name = "registration_time", nullable = false)
    public Date getRegistrationTime() {
	return this.registrationTime;
    }

    public void setRegistrationTime(Date registrationTime) {
	this.registrationTime = registrationTime;
    }

    @Basic
    @Column(nullable = false)
    public byte getStatus() {
	return this.status;
    }

    public void setStatus(Byte status) {
	this.status = status;
    }

    @Column(name = "username", nullable = false, length = 45)
    public String getUsername() {
	return this.username;
    }

    public void setUsername(String username) {
	this.username = username;
    }

    @Basic
    @Column(length = 45)
    public String getUserpic() {
	return this.userpic;
    }

    public void setUserpic(String userpic) {
	this.userpic = userpic;
    }

    // bi-directional many-to-many association to AccountRole
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @ManyToMany(cascade = { CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.MERGE }, fetch = FetchType.LAZY)
    @JoinTable(name = "user_role", schema = "community_dynamic", joinColumns = {
	    @JoinColumn(name = "user_id", nullable = false) }, inverseJoinColumns = {
		    @JoinColumn(name = "role_id", nullable = false) })
    public Set<RoleEntity> getRoles() {
	return this.roles;
    }

    public void setRoles(Set<RoleEntity> roles) {
	this.roles = roles;
    }
    
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @ManyToMany(cascade = { CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.MERGE }, fetch = FetchType.LAZY)
    @JoinTable(name = "black_list", schema = "community_dynamic", joinColumns = {
	    @JoinColumn(name = "user_id", nullable = false) }, inverseJoinColumns = {
		    @JoinColumn(name = "black_id", nullable = false) })
    public Set<UserEntity> getBlack() {
	return this.black;
    }

    public void setBlack(Set<UserEntity> black) {
	this.black = black;
    }
    
    
    @ManyToMany(mappedBy = "black")
    public Set<UserEntity> getBlacked() {
	return this.blacked;
    }

    public void setBlacked(Set<UserEntity> black) {
	this.blacked = black;
    }
    
    
    public UserEntity addBlack(UserEntity black) {
	this.getBlack().add(this.getBlack().stream().filter(entity -> entity.getId().equals(black.getId())).findAny().orElse(black));
	black.getBlacked().add(black.getBlacked().stream().filter(entity -> entity.getId().equals(this.getId())).findAny().orElse(this));

	return black;
    }

    public UserEntity removeBlack(UserEntity black) {
	this.getBlack().remove(this.getBlack().stream().filter(entity -> entity.getId().equals(black.getId())).findAny().get());
	black.getBlacked().remove(black.getBlacked().stream().filter(entity -> entity.getId().equals(this.getId())).findAny().get());
	return black;
    }
    
    
    public UserEntity addBlacked(UserEntity black) {
	this.getBlacked().add(black);
	black.getBlack().add(this);

	return black;
    }

    public UserEntity removeBlacked(UserEntity black) {
	this.getBlacked().remove(black);
	black.getBlack().remove(this);

	return black;
    }

    // bi-directional many-to-one association to AccountUserBind
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    public Set<UserBindEntity> getUserBinds() {
	return this.userBinds;
    }

    public void setUserBinds(Set<UserBindEntity> userBinds) {
	this.userBinds = userBinds;
    }

    public UserBindEntity addUserBind(UserBindEntity userBind) {
	this.getUserBinds().add(userBind);
	userBind.setUser(this);

	return userBind;
    }

    public UserBindEntity removeUserBind(UserBindEntity userBind) {
	this.getUserBinds().remove(userBind);
	userBind.setUser(null);

	return userBind;
    }

    // bi-directional one-to-one association to AccountUserinfo
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @OneToOne(cascade = { CascadeType.ALL }, fetch= FetchType.LAZY)
    @JoinColumn(name = "user_info_id", nullable = false)
    public UserInfoEntity getUserInfo() {
	return this.userInfo;
    }

    public void setUserInfo(UserInfoEntity userInfo) {
	this.userInfo = userInfo;
    }

    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    public Set<CommentEntity> getComments() {
        return comments;
    }

    public void setComments(Set<CommentEntity> comments) {
        this.comments = comments;
    }

    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    public Set<ImageEntity> getImages() {
        return images;
    }

    public void setImages(Set<ImageEntity> images) {
        this.images = images;
    }

    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    public Set<PostEntity> getPosts() {
        return posts;
    }

    public void setPosts(Set<PostEntity> posts) {
        this.posts = posts;
    }


    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @OneToMany(mappedBy = "from", fetch = FetchType.LAZY)
    public Set<FeedbackEntity> getFeedbacks() {
        return feedbacks;
    }

    public void setFeedbacks(Set<FeedbackEntity> feedbacks) {
        this.feedbacks = feedbacks;
    }

    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    @ManyToMany(cascade = { CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.MERGE }, fetch = FetchType.LAZY)
    @JoinTable(name = "follow", schema = "community_dynamic", joinColumns = {
	    @JoinColumn(name = "user_id", nullable = false) }, inverseJoinColumns = {
		    @JoinColumn(name = "follow_id", nullable = false) })
    public Set<UserEntity> getFollows() {
        return follows;
    }

    public void setFollows(Set<UserEntity> follows) {
        this.follows = follows;
    }

    @ManyToMany(mappedBy = "follows")
    public Set<UserEntity> getFolloweds() {
        return followeds;
    }

    public void setFolloweds(Set<UserEntity> followeds) {
        this.followeds = followeds;
    }
    
    public UserEntity addFollow(UserEntity follow) {
	this.getFollows().add(this.getFolloweds().stream().filter(entity -> entity.getId().equals(follow.getId())).findAny().orElse(follow));
	follow.getFolloweds().add(follow.getFolloweds().stream().filter(entity -> entity.getId().equals(this.getId())).findAny().orElse(this));
	return follow;
    }

    public UserEntity removeFollow(UserEntity follow) {
	this.getFollows().remove(this.getFollows().stream().filter(entity -> entity.getId().equals(follow.getId())).findAny().get());
	follow.getFolloweds().remove(follow.getFolloweds().stream().filter(entity -> entity.getId().equals(this.getId())).findAny().get());
	return follow;
    }
    
    
    public UserEntity addFollowed(UserEntity follow) {
	this.getFolloweds().add(follow);
	follow.getFollows().add(this);

	return follow;
    }

    public UserEntity removeFollowed(UserEntity follow) {
	this.getFolloweds().remove(follow);
	follow.getFollows().remove(this);

	return follow;
    }
    // bi-directional many-to-many association to AccountUser
    @ManyToMany(mappedBy = "supportUsers")
    public Set<PostEntity> getSupports() {
	return this.supports;
    }
    
    public void setSupports(Set<PostEntity> supports) {
	this.supports = supports;
    }

    
    // bi-directional many-to-many association to AccountUser
    @ManyToMany(mappedBy = "unSupportUsers")
    public Set<PostEntity> getUnSupports() {
	return this.unsupports;
    }
    
    public void setUnSupports(Set<PostEntity> unsupports) {
	this.unsupports = unsupports;
    }

}